from .base import *
from .pdn import PluginPDN
from .v2g import PluginV2G
from .dynps import PluginDynPs

class PluginMan:
    __curPlugins:dict[str,PluginBase] = {}
    __initPlugins = {
        "pdn": (PluginPDN,[]),
        "v2g": (PluginV2G,["pdn"]),
        "dynps": (PluginDynPs,["pdn"])
    }
    __avaPlugins = __initPlugins.copy()
    @staticmethod
    def ResetPlugins():
        '''重置插件列表'''
        PluginMan.__curPlugins = {}
        PluginMan.__avaPlugins = PluginMan.__initPlugins.copy()
    
    @staticmethod
    def LoadFromFile(plg_xml:str,inst:TrafficInst,no_plg:list[str]):
        '''
        从文件加载插件
            plg_xml: 插件配置文件路径
            inst: 交通仿真实例
            no_plg: 不加载的插件列表
        '''
        root = ET.ElementTree(file=plg_xml).getroot()
        work_dir = Path(plg_xml).parent
        assert root is not None, f"文件{plg_xml}不存在或已损坏"
        for itm in root:
            if itm.tag not in PluginMan.__avaPlugins: raise ValueError(f"无效插件{itm.tag}")
            if itm.tag in no_plg: continue
            dependencies = PluginMan.__avaPlugins[itm.tag][1]
            deps = []
            for d in dependencies:
                if d not in PluginMan.__curPlugins: raise ValueError(f"插件{itm.tag}依赖的插件{d}尚未加载")
                deps.append(PluginMan.__curPlugins[d])
            plugin_type = PluginMan.__avaPlugins[itm.tag][0]
            PluginMan.Add(plugin_type(inst,itm,work_dir,plugin_dependency=deps))
    
    @staticmethod
    def PreStepAll(_t:int)->dict[str,object]:
        '''执行所有插件PreStep, 返回所有插件的返回值'''
        ret:dict[str,object] = {}
        for k,p in PluginMan.__curPlugins.items():
            ret[k] = p._precall(_t)
        return ret
    
    @staticmethod
    def PostStepAll(_t:int)->dict[str,object]:
        '''执行所有插件PreStep, 返回所有插件的返回值'''
        ret:dict[str,object] = {}
        for k,p in PluginMan.__curPlugins.items():
            ret[k] = p._postcall(_t)
        return ret

    @staticmethod   
    def Register(name:str,plugin:PluginBase,deps:list[str]):
        '''将新的插件添加到可用插件列表, 便于从文件加载时使用'''
        assert plugin.Name not in PluginMan.__avaPlugins, f"插件{plugin.Name}已存在于可用插件列表"
        PluginMan.__avaPlugins[name] = (plugin,deps)
    
    @staticmethod   
    def Add(plugin:PluginBase):
        '''将新的插件添加到当前插件列表'''
        assert plugin.Name not in PluginMan.__curPlugins, f"插件{plugin.Name}已存在于当前插件列表"
        PluginMan.__curPlugins[plugin.Name] = plugin

    @staticmethod
    def GetByName(name:str)->PluginBase:
        '''通过插件名称获取插件'''
        return PluginMan.__curPlugins[name]
    
    @staticmethod
    def GetPlugins()->dict[str,PluginBase]:
        '''获取所有插件'''
        return PluginMan.__curPlugins
    
    @staticmethod
    def GetAvailablePlugins()->dict[str,tuple[PluginBase,list[str]]]:
        '''获取所有可用插件'''
        return PluginMan.__avaPlugins
